
#include <functional>
#include <iostream>

#include "rpcprovider.h"
#include "mrpcapplication.h"
#include "google/protobuf/descriptor.h"
#include "rpcheader.pb.h"
#include "user.pb.h"


void RpcProvider::notifyService(google::protobuf::Service *service)
{
    const google::protobuf::ServiceDescriptor *serviceDesc = service->GetDescriptor();
    ServiceInfo info;
    info._service = service;
    Methods methods;

    for (size_t i = 0; i < serviceDesc->method_count(); i++)
    {
        const google::protobuf::MethodDescriptor *currMethod = serviceDesc->method(i);
        methods.insert({currMethod->name(), currMethod});
        std::cout << serviceDesc->name() << ": methodName: [" << currMethod->name() << "]. add success!" << std::endl;
    }
    info._methods = methods;
    _serviceMap.insert({serviceDesc->name(), info});
}
void RpcProvider::run()
{
    // 启动muduo
    const std::string &ip = MrpcApplication::_conf.at("rpcserverip");
    uint16_t port = atoi(MrpcApplication::_conf.at("rpcserverport").c_str());
    muduo::net::InetAddress addr(ip.c_str(), port);

    muduo::net::TcpServer server(&_loop, addr, "RpcProvider");
    server.setThreadNum(4);
    server.setConnectionCallback(std::bind(&RpcProvider::setConnectionCallback, this, std::placeholders::_1));
    server.setMessageCallback(std::bind(&RpcProvider::setMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

    std::cout << "RpcProvider start ip: " << ip << ". port: " << port << std::endl;

    server.start();
    _loop.loop();
}

/**
 * 连接断开后，关闭连接
 */
void RpcProvider::setConnectionCallback(const muduo::net::TcpConnectionPtr &ptr)
{
    if (!ptr->connected())
    {
        std::cout << "conn shutdown" << std::endl;
        ptr->shutdown();
    }
}

/*std::string getTestMessage()
{
    // 硬编码的测试数据
    std::string serviceName = "UserServiceRpc";
    std::string methodName = "login";
    fixbug::LoginRequest *l = new fixbug::LoginRequest();
    l->set_username("zs");
    l->set_password("123");
    std::string args;
    l->SerializeToString(&args);

    // 创建并设置RpcHeader
    rpc::RpcHeader header;
    header.set_servicename(serviceName);
    header.set_methodname(methodName);
    header.set_argrsize(args.size());

    // 序列化header
    std::string headerStr;
    header.SerializeToString(&headerStr);

    // 获取header大小并转换为网络字节序
    uint32_t headerSize = headerStr.size();
    uint32_t netHeaderSize = htonl(headerSize);

    // 构建完整消息
    std::string allString;
    allString.append("0");
    allString.append(reinterpret_cast<const char *>(&netHeaderSize), 4);
    allString += headerStr;
    allString += args;

    std::cout << "headerStr = " << headerStr << std::endl;
    std::cout << "headerSize = " << headerSize << std::endl;
    std::cout << "netHeaderSize = " << netHeaderSize << std::endl;

    return allString;
}*/

/*std::string getTestMessageJson()
{
    // 硬编码的测试数据
    std::string serviceName = "UserService";
    std::string methodName = "login";
    std::string args = "{\"username\":\"zs\",\"password\":\"123\"}";
    int32_t argSize = args.size();
    std::string allString;

    std::unordered_map<std::string, std::string> head;
    head.insert({"serviceName", serviceName});
    head.insert({"methodName", methodName});
    head.insert({"argrSize", std::to_string(argSize)});
    json j = head;
    std::string headerStr = j.dump();

    uint32_t headerSize = headerStr.size();
    uint32_t netHeaderSize = htonl(headerSize);

    allString.append("1"); // json
    allString.append(reinterpret_cast<const char *>(&netHeaderSize), 4);
    allString += j.dump();
    allString += args;

    std::cout << "headerStr = " << j.dump() << std::endl;
    std::cout << "argrsize = " << argSize << std::endl;
    std::cout << "args = " << args << std::endl;

    return allString;
}*/

bool getDetailMessage(muduo::net::Buffer *buff, std::string &serviceName, std::string &methodName, std::string &argStr, int *formatInt)
{
    std::string allString = buff->retrieveAllAsString();

    // std::string allString = getTestMessage(); // 用于测试protobuff
    // std::string allString = getTestMessageJson(); // 用于测试json

    // 读取buff中第一个char 0=protobuff, 1=json
    std::cout << "buff : " << allString << std::endl;
    if (allString.length() <= 0)
        return false;
    *formatInt = allString[0] - '0';
    if (*formatInt != 0 && *formatInt != 1)
    {
        std::cout << "format error. formatInt = " << formatInt << std::endl;
        return false;
    }
    allString = allString.substr(1);
    std::string formatStr = *formatInt == 0 ? "protobuff" : "json";
    std::cout << "format : " << formatStr << std::endl;

    if (allString.size() < 4)
    {
        std::cout << "buff length < 4" << std::endl;
        return false;
    }
    // 取4字节获取args
    uint32_t netHeaderSize;
    // allString.copy((char*)headerSize, 4);
    std::memcpy(&netHeaderSize, allString.data(), 4); // 直接复制4字节到变量
    uint32_t headerSize = ntohl(netHeaderSize);
    std::string headerStr = allString.substr(4, headerSize);
    int argSize;
    if (*formatInt == 0)
    {
        rpc::RpcHeader head;
        if (head.ParseFromString(headerStr))
        {
            serviceName = head.servicename();
            methodName = head.methodname();
            argSize = head.argrsize();
        }
        else
        {
            std::cout << "parseString error. allString: " << allString << std::endl;
            return false;
        }
    }
    else
    {
        json headJson = json::parse(headerStr);
        serviceName = headJson["serviceName"];
        methodName = headJson["methodName"];
        std::string argSizeStr = headJson["argrSize"];
        argSize = std::stoi(argSizeStr);
    }
    argStr = allString.substr(headerSize + 4, argSize);

    std::cout << "allString:  " << allString << std::endl;
    std::cout << "serviceName:  " << serviceName << std::endl;
    std::cout << "methodName:  " << methodName << std::endl;
    std::cout << "argStr:  " << argStr << std::endl;
    return true;
}

bool RpcProvider::getDetailMethod(std::string &serviceName,
                                  std::string &methodName,
                                  google::protobuf::Service *&currService,
                                  const google::protobuf::MethodDescriptor *&currMethod,
                                  int formatInt)
{
    auto service = _serviceMap.find(serviceName);
    if (service == _serviceMap.end())
    {
        std::cout << "Service not found: " << serviceName << std::endl;
        return false;
    }
    ServiceInfo serviceInfo = service->second;
    currService = serviceInfo._service;

    Methods methods = serviceInfo._methods;
    auto method = methods.find(methodName);
    if (method == methods.end())
    {
        std::cout << "method not found: " << methodName << std::endl;
        return false;
    }
    currMethod = method->second;
    return true;
}

bool RpcProvider::executeMethod(google::protobuf::Service *&currService,
                                const google::protobuf::MethodDescriptor *&currMethod,
                                std::string &argStr,
                                const muduo::net::TcpConnectionPtr &ptr,
                                int formatInt)
{
    google::protobuf::Message *request = currService->GetRequestPrototype(currMethod).New();
    // request->GetTypeName()
    if (!request->ParseFromString(argStr))
    {
        std::cout << "parse error. argStr: " << argStr << std::endl;
        return false;
    }

    google::protobuf::Message *response = currService->GetResponsePrototype(currMethod).New();

    request->ParseFromString(argStr);
    // 成功执行后将反参返回去
    // 使用自定义 Closure 类包装回调函数
    std::unique_ptr<std::string> responseStr;
    google::protobuf::Closure *done = google::protobuf::NewCallback<RpcProvider, const muduo::net::TcpConnectionPtr &, google::protobuf::Message *>(
        this,
        &RpcProvider::sendResponse,
        ptr,
        response);
    // responseStr);

    // 将响应序列化并发送回客户端
    currService->CallMethod(currMethod, nullptr, request, response, done);

    return true;
}

void RpcProvider::sendResponse(const muduo::net::TcpConnectionPtr &ptr, google::protobuf::Message *response)
{
    if (!ptr || !ptr->connected())
    {
        std::cout << "Connection is invalid or closed" << std::endl;
        return;
    }

    std::string responseStr;
    if (response->SerializeToString(&responseStr))
    {
        ptr->send(responseStr);
    }
    else
    {
        std::cout << "SerializeAsString error, type : " << response->GetTypeName() << std::endl;
    }

    ptr->shutdown();
}

void RpcProvider::executeJsonMethod(std::string &serviceName,
                                    std::string &methodName,
                                    std::string &argStr,
                                    const muduo::net::TcpConnectionPtr &ptr)
{
    std::unordered_map<std::string, std::unique_ptr<JsonService>> &serviceMap = RpcProvider::getServiceJsonMap();
    auto service = serviceMap.find(serviceName);
    if (service == serviceMap.end())
    {
        std::cout << "Service not found: " << serviceName << std::endl;
        return;
    }

    std::unique_ptr<JsonService> &serviceInfo = service->second;
    JsonResponse jsonResponse;
    RpcJsonParam param;

    std::cout << "source: " << argStr << std::endl;
    std::cout << "once : " << json::parse(argStr).dump() << std::endl;
    std::cout << "once : " << json::parse(json::parse(argStr).get<std::string>()).dump() << std::endl;

    // 原理待处理 todo
    //{"password":"123","username":"zs"} 不行
    // param.requestJson = json::parse(argStr); // 这样不行

    // {\"password\":\"123\",\"username\":\"zs\"} 行
    // param.requestJson = json::parse(json::parse(argStr).get<std::string>());

    // 这样行
    param.requestJson = json::parse(json::parse(argStr).get<std::string>());
    param.response = jsonResponse;
    serviceInfo->call(methodName, param);

    std::cout << "json message: " << param.response.message << std::endl;
    std::cout << "json success: " << param.response.success << std::endl;
    std::cout << "json dataJson: " << param.response.dataJson << std::endl;

    if (!ptr || !ptr->connected())
    {
        std::cout << "Connection is invalid or closed" << std::endl;
        return;
    }

    // 序列化后返回
    json result = param.response;
    std::string responseStr = result.dump();
    ptr->send(responseStr);
    ptr->shutdown();
}

/**
 * 1. 取出本次接收到的数据
 * 2. 根据数据获取实际的service和method
 * 3. 执行具体的method并使用muduo返回数据
 * serviceName methodName args
 * buff规则(destory)： args(4个字节) header_str12 args_str   (这里的12代指args_size)
 *         例如： 4UserServicelogin5 zs123
 * buff规则：format(int: 0=protobuff, 1=json) args(4个字节) header_str12 args_str   (这里的12代指args_size)
 *         例如： 04UserServicelogin5 zs123
 * buff规则（json）：format+args(4个字节)+{"serviceName":"","methodName":"", "argSize":""}+args_str(json)
 *
 */
void RpcProvider::setMessageCallback(const muduo::net::TcpConnectionPtr &ptr,
                                     muduo::net::Buffer *buff,
                                     muduo::Timestamp)
{

    int formatInt = 0;
    // 1. 获取实际信息
    std::string serviceName, methodName, argStr;
    if (!getDetailMessage(buff, serviceName, methodName, argStr, &formatInt))
        return;

    // 2. 获取实际 service method 并执行
    if (formatInt == 1)
    {
        executeJsonMethod(serviceName, methodName, argStr, ptr);
    }
    else
    {
        google::protobuf::Service *currService;
        const google::protobuf::MethodDescriptor *currMethod;
        if (!getDetailMethod(serviceName, methodName, currService, currMethod, formatInt))
            return;
        if (!executeMethod(currService, currMethod, argStr, ptr, formatInt))
            return;
    }

    

    std::cout << "setMessageCallback end!" << std::endl;
}

RpcProvider::RpcProvider(/* args */)
{
}
RpcProvider::~RpcProvider()
{
}

